#ifndef OMG_DDS_PUBLISHER_HPP_
#define OMG_DDS_PUBLISHER_HPP_

/* Copyright (c) 2009-2010, Real-Time Innovations, Inc.
 * Copyright (c) 2010, Object Management Group, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - Neither the names of the above copyright holders nor the names of their
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL A COPYRIGHT HOLDER OR CONTRIBUTOR BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */


/**
 * The Publisher acts on the behalf of one or several DataWriter objects 
 * that belong to it. When it is informed of a change to the data associated 
 * with one of its DataWriter objects, it decides when it is appropriate 
 * to actually send the data-update message. In making this decision, it 
 * considers any extra information that goes with the data (timestamp, 
 * writer, etc.) as well as the QoS of the Publisher and the DataWriter.
 */
template <typename DELEGATE>
class tdds::pub::Publisher : public dds::core::Entity
{
    OMG_DDS_REFERENCE_TYPE(Publisher)

public:
    typedef dds::core::StatusCondition<Publisher> StatusConditionType;
    
public:
    /**
     * This operation retrieves all previously created DataWriter belonging 
     * to the Publisher that is attached to a Topic with a matching 
     * topic_name. If no such DataWriter exists, the operation will return
     * an empty container.
     *
     * @param topic_name the Topic name.
     * @return the sequence of writer created for the given topic.
     */
    template <typename T>
    dds::pub::DataWriter<T>
    lookup_datawriter(const std::string& topic_name) const;

    template <typename T>
    dds::pub::DataWriter<T>
    lookup_datawriter(const dds::topic::Topic<T>& topic) const;

    dds::type::builtin::StringDataWriter
    lookup_datawriter(const dds::topic::Topic<std::string>& topic) const;
    
    dds::type::builtin::KeyedStringDataWriter
    lookup_datawriter(
        const dds::topic::Topic<dds::type::builtin::KeyedString>& topic) const;
    
    dds::type::builtin::BytesDataWriter
    lookup_datawriter(
        const dds::topic::Topic<dds::core::ByteSeq>& topic) const;

    dds::type::builtin::KeyedBytesDataWriter
    lookup_datawriter(
        const dds::topic::Topic<dds::type::builtin::KeyedBytes>& topic) const;
    
    /**
     * This operation blocks the calling thread until either all data
     * written by the reliable DataWriter entities is acknowledged by all
     * matched reliable DataReader entities, or else the duration
     * specified by the max_wait parameter elapses, whichever happens
     * first. A return value of OK indicates that all the samples written
     * have been acknowledged by all reliable matched data readers; a
     * return value of TIMEOUT indicates that max_wait elapsed before all
     * the data was acknowledged.
     */
    void wait_for_acknowledgments(const dds::core::Duration& max_wait);

    template <typename T>
    dds::pub::DataWriter<T> create_datawriter(
        const dds::topic::Topic<T>& a_topic);
    template <typename T>
    dds::pub::DataWriter<T> create_datawriter(
        const dds::topic::Topic<T>& a_topic, 
        const dds::pub::DataWriterQos& a_qos,
        dds::pub::DataWriterListener<T>* a_listener   = NULL,
        const dds::core::StatusMask& a_mask = dds::core::StatusMask::all());
    template <typename T>
    dds::pub::DataWriter<T> create_datawriter(
        const dds::topic::Topic<T>& a_topic, 
        const std::string& qos_library_name,
        const std::string& qos_profile_name,
        dds::pub::DataWriterListener<T>* a_listener   = NULL,
        const dds::core::StatusMask& a_mask = dds::core::StatusMask::all());

    dds::type::builtin::StringDataWriter create_datawriter(
        const dds::topic::Topic<std::string>& a_topic);
    dds::type::builtin::StringDataWriter create_datawriter(
        const dds::topic::Topic<std::string>& a_topic, 
        const dds::pub::DataWriterQos& a_qos,
        dds::pub::DataWriterListener<std::string>* a_listener   = NULL,
        const dds::core::StatusMask& a_mask = dds::core::StatusMask::all());
    dds::type::builtin::StringDataWriter create_datawriter(
        const dds::topic::Topic<std::string>& a_topic, 
        const std::string& qos_library_name,
        const std::string& qos_profile_name,
        dds::pub::DataWriterListener<std::string>* a_listener   = NULL,
        const dds::core::StatusMask& a_mask = dds::core::StatusMask::all());

    dds::type::builtin::KeyedStringDataWriter create_datawriter(
        const dds::topic::Topic<dds::type::builtin::KeyedString>& a_topic);
    dds::type::builtin::KeyedStringDataWriter create_datawriter(
        const dds::topic::Topic<dds::type::builtin::KeyedString>& a_topic, 
        const dds::pub::DataWriterQos& a_qos,
        dds::pub::DataWriterListener<dds::type::builtin::KeyedString>* a_listener   = NULL,
        const dds::core::StatusMask& a_mask = dds::core::StatusMask::all());
    dds::type::builtin::KeyedStringDataWriter create_datawriter(
        const dds::topic::Topic<dds::type::builtin::KeyedString>& a_topic, 
        const std::string& qos_library_name,
        const std::string& qos_profile_name,
        dds::pub::DataWriterListener<dds::type::builtin::KeyedString>* a_listener   = NULL,
        const dds::core::StatusMask& a_mask = dds::core::StatusMask::all());

    dds::type::builtin::BytesDataWriter create_datawriter(
        const dds::topic::Topic<dds::core::ByteSeq>& a_topic);
    dds::type::builtin::BytesDataWriter create_datawriter(
        const dds::topic::Topic<dds::core::ByteSeq>& a_topic, 
        const dds::pub::DataWriterQos& a_qos,
        dds::pub::DataWriterListener<dds::core::ByteSeq>* a_listener   = NULL,
        const dds::core::StatusMask& a_mask = dds::core::StatusMask::all());
    dds::type::builtin::BytesDataWriter create_datawriter(
        const dds::topic::Topic<dds::core::ByteSeq>& a_topic, 
        const std::string& qos_library_name,
        const std::string& qos_profile_name,
        dds::pub::DataWriterListener<dds::core::ByteSeq>* a_listener   = NULL,
        const dds::core::StatusMask& a_mask = dds::core::StatusMask::all());

    dds::type::builtin::KeyedBytesDataWriter create_datawriter(
        const dds::topic::Topic<dds::type::builtin::KeyedBytes>& a_topic);
    dds::type::builtin::KeyedBytesDataWriter create_datawriter(
        const dds::topic::Topic<dds::type::builtin::KeyedBytes>& a_topic, 
        const dds::pub::DataWriterQos& a_qos,
        dds::pub::DataWriterListener<dds::type::builtin::KeyedBytes>* a_listener   = NULL,
        const dds::core::StatusMask& a_mask = dds::core::StatusMask::all());
    dds::type::builtin::KeyedBytesDataWriter create_datawriter(
        const dds::topic::Topic<dds::type::builtin::KeyedBytes>& a_topic, 
        const std::string& qos_library_name,
        const std::string& qos_profile_name,
        dds::pub::DataWriterListener<dds::type::builtin::KeyedBytes>* a_listener   = NULL,
        const dds::core::StatusMask& a_mask = dds::core::StatusMask::all());

    const dds::pub::DataWriterQos get_default_datawriter_qos() const;
    void set_default_datawriter_qos(const dds::pub::DataWriterQos& a_qos);
    void set_default_datawriter_qos(const std::string& qos_library_name,
                                    const std::string& qos_profile_name);

    // --- Entity methods: --- //
public:
    /**
     * This method closes the entity and releases all resources associated with
     * DDS, such as threads, sockets, buffers, etc. Any attempt to invoke
     * methods on a closed entity will raise an AlreadyClosedError.
     */
    virtual void close();
    
    StatusConditionType get_statuscondition();

    using dds::core::Entity::set_qos;
    void set_qos(const dds::pub::PublisherQos& qos);
    const dds::pub::PublisherQos get_qos() const;

    void set_listener(dds::pub::PublisherListener* l,
                      const dds::core::StatusMask& mask = dds::core::StatusMask::all());

    dds::pub::PublisherListener* get_listener() const;

    /**
     * This operation returns the DomainParticipant to which the Publisher
     * belongs.
     */
    dds::domain::DomainParticipant get_parent() const;

    // --- State: --- //
private:
    friend class OMG_DDS_PUBLISHER_DELEGATE;
    DELEGATE impl_;
};


#endif // !defined(OMG_DDS_PUBLISHER_HPP_)
